成品連結:Sticky Nav、操作前程式碼 - HTML、操作前程式碼 - CSS、操作後程式碼 - HTML、操作後程式碼 - CSS
今天要做的是類似 CSS 中的 position: fixed
的功能,只不過需滾動至特定的位置才會開始生效。看到這裡或許你會說那就用 position: sticky
就好啦!沒錯,的確可行,但我們還是嘗試使用 JS 實作吧!
scroll
)事件首先設定滾動監聽事件
function stickyNav() {
// code here
}
window.addEventListener('scroll', stickyNav);
接著要來設定效果生效的位置。我們要先知道當滾動至哪個距離時會開始生效,這裡有兩個辦法,
header
的高度(offsetHeight
)nav
與網頁頂部的距離(offsetTop
)今天我們會使用的是第二種方法(第一種方法請自行嘗試)。
先取得 nav
與網頁頂部的距離
const nav = document.querySelector('#main');
const topOfNav = nav.offsetTop;
function stickyNav() {
// code here
}
接著使用 if...else...
來判斷當滾動距離大於或等於 nav.topOfNav
時生效
const nav = document.querySelector('#main');
const topOfNav = nav.offsetTop;
function stickyNav() {
if (window.scrollY >= topOfNav) {
// code here
} else {
// code here
}
}
這裡要注意必須在 function 外面宣告及賦值給 topOfNav
而不能直接在 if...else...
中比較(if (window.scrollY >= nav.offsetTop){..}
);因為如果直接在 if...
中比較,nav.offsetTop
會隨著滾動越來越小,即便你向上滾動也不會變大(根本原因是設定在監聽事件內,nav.offsetTop
會持續變動,終至 0),所以要將該變數宣告在 function 外面
我們要讓 Navbar 固定的方法就是使用 position: fixed
(請暫時忘記 position: sticky
的存在)
/* CSS */
.fixed-nav nav {
position: fixed;
box-shadow: 0 5px rgba(0,0,0,0.1);
}
並加到 JS 中
這裡會把 .fixed-nav
這個 class 加到 body
而不是 nav
是因為如果是加到 nav
,那晚點要操作其他元素時會很不方便(需要向上一層 -> 接著再找要設定的元素),綁在 body
並透果選擇器選到要設定樣式的元素會較恰當
function stickyNav() {
if (window.scrollY >= topOfNav) {
document.body.classList.add('fixed-nav');
} else {
document.body.classList.remove('fixed-nav');
}
}
有效果出來了,但怎麼感覺當滾動到該位置時下方的文字區塊會向上跑動?你沒看錯,這是因為當 nav
變成 position: fixed
時它浮起來了,換另一種方式講就是 nav
變得不佔據 HTML 的空間,也因此下方的元素就跑上去了。
所以我們要把 nav
的高度加回去在 body
的 padding-top
,這裡提醒一下千萬不要在 CSS 寫死值,要是之後 nav
高度改變會變得很難修改。應該說當一個元素的值可能變動時都不要寫死值,而是要用變數的方式使之更有彈性。
function stickyNav() {
if (window.scrollY >= topOfNav) {
document.body.classList.add('fixed-nav');
document.body.style.paddingTop = `${nav.offsetHeight}px`;
} else {
document.body.classList.remove('fixed-nav');
document.body.style.paddingTop = `0px`;
}
}
其實到這裡功能差不多做完了,但如果 HTML 看得仔細的話會看到 nav ul
當中第一項的 li
是沒有在畫面上的,這是因為 CSS 設定 max-width: 0
所以看不到,而我要把它加回去。
/* CSS */
.fixed-nav .logo {
max-width: 500px;
}
透過更改 max-width
屬性,現在當滾動至一定位置,logo 出現了!
最後當滾動至一定位置時,啟用效果使下方文字有放大效果。
從 CSS 可以看到 .site-wrap
有一個屬性是 transform: scale(0.98)
,而我們要將它稍微放大
/* CSS */
.fixed-nav .site-wrap {
transform: scale(1);
}
這樣就完成啦!
這裡順便留個小任務給各位,如果使用 position: sticky
要如何做出相同效果呢?請練習看看~
如果有不清楚的地方歡迎留言詢問喔!